<?php
declare(strict_types=1);

namespace App\Common\Extend\Guard;

use App\Application;
use App\Common\Modular\Administer\Model\LogModel;
use Core\HyperfUnit\Client;
use Core\HyperfUnit\Ip;
use Core\System\AuthUnit;
use Hyperf\Di\Annotation\Aspect;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Di\Aop\{AbstractAspect, ProceedingJoinPoint};
use Hyperf\Di\Exception\Exception;
use Hyperf\HttpMessage\Server\Response;
use Hyperf\HttpServer\Contract\RequestInterface;
use Zms\Exception\{AppException, DataException, ExpireLoggedInException, NotLoggedException};
use Zms\Unit\Json;
use function Hyperf\Coroutine\go;
use function Hyperf\Support\env;

#[Aspect(priority: 100)]
class AuthAspect extends AbstractAspect
{

    /**
     * 要切入的注解
     * @var array
     */
    public array $annotations = [
        Auth::class
    ];
    #[Inject]
    protected RequestInterface $request;

    /**
     * @param ProceedingJoinPoint $proceedingJoinPoint
     * @return mixed
     * @throws AppException
     * @throws Exception
     * @throws ExpireLoggedInException
     * @throws NotLoggedException
     * @throws DataException
     */
    public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed
    {
        $permissions = AuthUnit::getActionPermissions($proceedingJoinPoint->className, $proceedingJoinPoint->methodName);
        if ($permissions === null) {
            return $proceedingJoinPoint->process();
        }
        $guard = guard($permissions['guard']);
        $permissions['user_id'] = $guard->tourist() === true ? -1 : $guard->uid();
        if ($permissions['process'] === false) {
            $this->logger($permissions);
            return $proceedingJoinPoint->process();
        }
        if (is_null($permissions)) {//没有有效节点权限
            $permissions['result'] = $proceedingJoinPoint->process();
            $this->logger($permissions);
            return $permissions['result'];
        }
        if ($permissions['tourist'] === true) {//允许游客访问
            $permissions['result'] = $proceedingJoinPoint->process();
            $this->logger($permissions);
            return $permissions['result'];
        }
        if (!(in_array('*', $permissions['mode']) || in_array(env('APP_ENV'), $permissions['mode']))) {//判断接口是否环境可用
            throw new AppException('当前环境不允许访问');
        }
        if ($permissions['user_id'] === -1) {//未登录
            $this->request->hasHeader('auth-token') ? throw new ExpireLoggedInException() : throw new NotLoggedException();
        }
        if ($permissions['check'] === true && $permissions['sign'] && $permissions['sign'] !== 'skip') {
            if ($guard->user()->authorize($permissions)) {//权限验证
                $permissions['result'] = $proceedingJoinPoint->process();
                $this->logger($permissions);
                return $permissions['result'];
            }
        } else {//无需权限,自定义验证
            $permissions['result'] = $proceedingJoinPoint->process();
            $this->logger($permissions);
            return $permissions['result'];
        }
        throw new AppException('你没有访问权限');

    }


    /**
     * 记录日志
     * @param array $permissions
     * @return void
     */
    public function logger(array $permissions): void
    {
        if ($permissions['logger'] === false) {
            return;//未开启记录
        }
        $permissions['status'] = 1;
        $permissions['msg'] = '';
        if (isset($permissions['result']) && $permissions['result'] instanceof Response) {
            $body = Json::decode($permissions['result']->getBody()->getContents());
            $code = intval($body['code'] ?? 200);
            $permissions['msg'] = mb_substr($body['msg'] ?? '', 0, 50);
            $permissions['status'] = $code === 200;
        }
        $permissions['method'] = $this->request->getMethod();
        if (($permissions['logger'] === 'GET' || $permissions['logger'] === 'get') && $permissions['method'] !== 'GET') {
            return;//记录条件不符
        }
        if (($permissions['logger'] === 'POST' || $permissions['logger'] === 'post') && $permissions['method'] !== 'POST') {
            return;//记录条件不符
        }
        $permissions['param'] = $permissions['record'] ? $this->request->inputs($permissions['record']) : $this->request->all();
        $permissions['ip'] = Ip::getIp();
        $permissions['url'] = $this->request->getUri()->getPath();
        $permissions['os'] = Client::os();
        $permissions['browser'] = Client::browser();
        $permissions['describe'] = Application::getLog() ?: $permissions['describe'];//如果手动设置了数据
        go(function () use ($permissions) {
            $model = new LogModel();
            $model->name = $permissions['describe'] ?: implode('/', $permissions['name']);
            $model->callback = $permissions['class'] . '::' . $permissions['action'];
            $model->method = $permissions['method'];
            $model->msg = $permissions['msg'];
            $model->status = $permissions['status'];
            $model->url = $permissions['url'];
            $model->param = $permissions['param'];
            $model->browser = $permissions['browser'];
            $model->ip = $permissions['ip'];
            $model->user_id = $permissions['user_id'];
            $model->os = $permissions['os'];
            $model->guard = $permissions['guard'];
            $model->app = $permissions['app'];
            $model->time = time();
            $model->save();
        });
    }
}